/*
 * @Author: liaoyu1992 1519778181@qq.com
 * @Date: 2022-11-03 22:55:11
 * @LastEditors: liaoyu1992 1519778181@qq.com
 * @LastEditTime: 2022-11-09 13:57:34
 * @FilePath: \kgantt\core\helpers\barHelpers.ts
 * @Description: 日期工具类
 */
import { Task, ViewMode } from "../types/publicTypes";
import DateTimeFormatOptions = Intl.DateTimeFormatOptions;
import DateTimeFormat = Intl.DateTimeFormat;
type DateHelperScales =
    | "year"
    | "month"
    | "day"
    | "hour"
    | "minute"
    | "second"
    | "millisecond";
const intlDTCache = new Map<String, any>();
export const getCachedDateTimeFormat = (
    locString: string | string[],
    opts: DateTimeFormatOptions = {}
): DateTimeFormat => {
    const key = JSON.stringify([locString, opts]);
    let dtf = intlDTCache.get(key);
    if (!dtf) {
        dtf = new Intl.DateTimeFormat(locString, opts);
        intlDTCache.set(key, dtf);
    }
    return dtf;
};
export const addToDate = (
    date: Date,
    quantity: number,
    scale: DateHelperScales
) => {
    const newDate = new Date(
        date.getFullYear() + (scale === "year" ? quantity : 0),
        date.getMonth() + (scale === "month" ? quantity : 0),
        date.getDate() + (scale === "day" ? quantity : 0),
        date.getHours() + (scale === "hour" ? quantity : 0),
        date.getMinutes() + (scale === "minute" ? quantity : 0),
        date.getSeconds() + (scale === "second" ? quantity : 0),
        date.getMilliseconds() + (scale === "millisecond" ? quantity : 0)
    );
    return newDate;
};

export const startOfDate = (date: Date, scale: DateHelperScales) => {
    const scores = [
        "millisecond",
        "second",
        "minute",
        "hour",
        "day",
        "month",
        "year",
    ];

    const shouldReset = (_scale: DateHelperScales) => {
        const maxScore = scores.indexOf(scale);
        return scores.indexOf(_scale) <= maxScore;
    };
    const newDate = new Date(
        date.getFullYear(),
        shouldReset("year") ? 0 : date.getMonth(),
        shouldReset("month") ? 1 : date.getDate(),
        shouldReset("day") ? 0 : date.getHours(),
        shouldReset("hour") ? 0 : date.getMinutes(),
        shouldReset("minute") ? 0 : date.getSeconds(),
        shouldReset("second") ? 0 : date.getMilliseconds()
    );
    return newDate;
};

export const ganttDateRange = (
    tasks: Task[],
    viewMode: ViewMode,
    preStepsCount: number
) => {
    let newStartDate: Date = tasks[0].start;
    let newEndDate: Date = tasks[0].start;
    for (const task of tasks) {
        if (task.start < newStartDate) {
            newStartDate = task.start;
        }
        if (task.end > newEndDate) {
            newEndDate = task.end;
        }
    }
    switch (viewMode) {
        case ViewMode.Year:
            newStartDate = addToDate(newStartDate, -1, "year");
            newStartDate = startOfDate(newStartDate, "year");
            newEndDate = addToDate(newEndDate, 1, "year");
            newEndDate = startOfDate(newEndDate, "year");
            break;
        case ViewMode.Month:
            newStartDate = addToDate(newStartDate, -1 * preStepsCount, "month");
            newStartDate = startOfDate(newStartDate, "month");
            newEndDate = addToDate(newEndDate, 1, "year");
            newEndDate = startOfDate(newEndDate, "year");
            break;
        case ViewMode.Week:
            newStartDate = startOfDate(newStartDate, "day");
            newStartDate = addToDate(
                getMonday(newStartDate),
                -7 * preStepsCount,
                "day"
            );
            newEndDate = startOfDate(newEndDate, "day");
            newEndDate = addToDate(newEndDate, 1.5, "month");
            break;
        case ViewMode.Day:
            newStartDate = startOfDate(newStartDate, "day");
            newStartDate = addToDate(newStartDate, -1 * preStepsCount, "day");
            newEndDate = startOfDate(newEndDate, "day");
            newEndDate = addToDate(newEndDate, 19, "day");
            break;
        case ViewMode.QuarterDay:
            newStartDate = startOfDate(newStartDate, "day");
            newStartDate = addToDate(newStartDate, -1 * preStepsCount, "day");
            newEndDate = startOfDate(newEndDate, "day");
            newEndDate = addToDate(newEndDate, 66, "hour"); // 24(1 day)*3 - 6
            break;
        case ViewMode.HalfDay:
            newStartDate = startOfDate(newStartDate, "day");
            newStartDate = addToDate(newStartDate, -1 * preStepsCount, "day");
            newEndDate = startOfDate(newEndDate, "day");
            newEndDate = addToDate(newEndDate, 108, "hour"); // 24(1 day)*5 - 12
            break;
        case ViewMode.Hour:
            newStartDate = startOfDate(newStartDate, "hour");
            newStartDate = addToDate(newStartDate, -1 * preStepsCount, "hour");
            newEndDate = startOfDate(newEndDate, "day");
            newEndDate = addToDate(newEndDate, 1, "day");
            break;
    }
    return [newStartDate, newEndDate];
};

export const seedDates = (
    startDate: Date,
    endDate: Date,
    viewMode: ViewMode
) => {
    let currentDate: Date = new Date(startDate);
    const dates: Date[] = [currentDate];
    while (currentDate < endDate) {
        switch (viewMode) {
            case ViewMode.Year:
                currentDate = addToDate(currentDate, 1, "year");
                break;
            case ViewMode.Month:
                currentDate = addToDate(currentDate, 1, "month");
                break;
            case ViewMode.Week:
                currentDate = addToDate(currentDate, 7, "day");
                break;
            case ViewMode.Day:
                currentDate = addToDate(currentDate, 1, "day");
                break;
            case ViewMode.HalfDay:
                currentDate = addToDate(currentDate, 12, "hour");
                break;
            case ViewMode.QuarterDay:
                currentDate = addToDate(currentDate, 6, "hour");
                break;
            case ViewMode.Hour:
                currentDate = addToDate(currentDate, 1, "hour");
                break;
        }
        dates.push(currentDate);
    }
    return dates;
};

export const getLocaleMonth = (date: Date, locale: string) => {
    let bottomValue = getCachedDateTimeFormat(locale, {
        month: "long",
    }).format(date);
    bottomValue = bottomValue.replace(
        bottomValue[0],
        bottomValue[0].toLocaleUpperCase()
    );
    return bottomValue;
};

export const getLocalDayOfWeek = (
    date: Date,
    locale: string,
    format?: "long" | "short" | "narrow" | undefined
) => {
    let bottomValue = getCachedDateTimeFormat(locale, {
        weekday: format,
    }).format(date);
    bottomValue = bottomValue.replace(
        bottomValue[0],
        bottomValue[0].toLocaleUpperCase()
    );
    return bottomValue;
};

/**
 * 获取周一
 * @param date 修改日期
 */
const getMonday = (date: Date) => {
    const day = date.getDay();
    const diff = date.getDate() - day + (day === 0 ? -6 : 1); // adjust when day is sunday
    return new Date(date.setDate(diff));
};

export const getWeekNumberISO8601 = (date: Date) => {
    const tmpDate = new Date(date.valueOf());
    const dayNumber = (tmpDate.getDay() + 6) % 7;
    tmpDate.setDate(tmpDate.getDate() - dayNumber + 3);
    const firstThursday = tmpDate.valueOf();
    tmpDate.setMonth(0, 1);
    if (tmpDate.getDay() !== 4) {
        tmpDate.setMonth(0, 1 + ((4 - tmpDate.getDay() + 7) % 7));
    }
    const weekNumber = (
        1 + Math.ceil((firstThursday - tmpDate.valueOf()) / 604800000)
    ).toString();

    if (weekNumber.length === 1) {
        return `0${weekNumber}`;
    } else {
        return weekNumber;
    }
};

export const getDaysInMonth = (month: number, year: number) => {
    return new Date(year, month + 1, 0).getDate();
};

export function getStartEndDateForProject(tasks: Task[], projectId: string) {
    const projectTasks = tasks.filter(t => t.project === projectId);
    let start = projectTasks[0].start;
    let end = projectTasks[0].end;

    for (let i = 0; i < projectTasks.length; i++) {
        const task = projectTasks[i];
        if (start.getTime() > task.start.getTime()) {
            start = task.start;
        }
        if (end.getTime() < task.end.getTime()) {
            end = task.end;
        }
    }
    return [start, end];
}


export function dateToDateString(date: Date) {
    var year = date.getFullYear();
    var month = (date.getMonth() + 1).toString();
    var day = (date.getDate()).toString();
    if (month.length == 1) {
        month = "0" + month;
    }
    if (day.length == 1) {
        day = "0" + day;
    }
    var dateTime = year + "-" + month + "-" + day ;
    return dateTime;
}
export function dateToDateTimeString(date: Date) {
    var year = date.getFullYear();
    var month = (date.getMonth() + 1).toString();
    var day = (date.getDate()).toString();
    if (month.length == 1) {
        month = "0" + month;
    }
    if (day.length == 1) {
        day = "0" + day;
    }
    var hours = date.getHours().toString();
    if (hours.length == 1) {
        hours = "0" + hours;
    }
    var mintus = date.getMinutes().toString();
    if (mintus.length == 1) {
        mintus = "0" + mintus;
    }
    var second = date.getSeconds().toString();
    if (second.length == 1) {
        second = "0" + second;
    }
    var dateTime = year + "-" + month + "-" + day + " " + hours + ":" + mintus + ":" + second;
    return dateTime;
}